class Engine{

  frameRate = 60;
  timeGap = 1/this.frameRate;

  assets;
  map;
  room;


  msgs = {};


  start(){
    let that = this;
    setInterval(function(){
      that.run();
    },this.timeGap);
  }
  notify(){
    for(let key in this.msgs){
      this.room.players[key].uiEle(this.msgs[key].uilist);
    }
  }

  uiEle(ele){
    for(let key in this.msgs){
      this.msgs[key].uilist.push(ele);
    }
  }

  initMsgs(){
    this.msgs = {};
    for(let key in this.room.players){
      this.msgs[key] = {};
      this.msgs[key].uilist=[];
      this.msgs[key].rmlist=[];
    }

  }


  run(){
    this.initMsgs();
    this.move();
    this.notify();
  }
  move(){
    for(let key in this.assets.roles){
      let role = this.assets.roles[key];
      if(role.vx == 0 && role.vy == 0){
        continue;
      }
      role.shape.x = role.shape.x + role.vx * this.timeGap * role.vrate;
      role.shape.y = role.shape.y + role.vy * this.timeGap * role.vrate;

      if(role.shape.x >= this.map.width){
        role.shape.x = this.map.width;
      }
      if(role.shape.x <= 0){
        role.shape.x = 0;
      }
      if(role.shape.y >= this.map.height){
        role.shape.y = this.map.height;
      }
      if(role.shape.y <= 0){
        role.shape.y = 0;
      }
      this.uiEle(role)
    }
  }
}


class Assets{
  roles={};
  buildings={};
  elements={};
  grids;

}

class Room{
  name;
  admin;
  map;
  engine;
  runner;
  assets;
  operator;
  players={};

  constructor(){
    this.map = new Map();
    this.assets = new Assets();
    this.map.assets=this.assets;
    this.map.initAssets();
    this.map.addGrids(this.assets);
    this.engine = new Engine();
    this.engine.assets = this.assets;
    this.engine.room = this;
    this.engine.map = this.map;
    this.engine.start();
    
  }

  addPlayer(player){
    this.players[player.name]=player;
  }

  getEleId(){
    return this.map.eleId++;
  }

}

class Player{
  address;
  name;
  room;
  role;
  ws;
  inG = false;

  constructor(name,ws){
    this.address = name;
    this.name = name;
    this.ws = ws;
  }

  startg(){

    if(this.inG){
      return;
    }
    this.inG = true;
    let cmd = {"type":"uiEle"};
    let data = [];
    let ele = new Ele();
    ele.type = "role";
    ele.id = "e"+this.room.getEleId();


    this.role.body = ele;
    this.room.assets.roles[ele.id] = ele;

    data.push(ele);
    cmd.data = data;
    this.ws.send(JSON.stringify(cmd));
  }

  move(vx , vy){
    this.role.body.vx = vx;
    this.role.body.vy = vy;
  }

  uiEle(data){
    if(!data || data.length == 0){
      return;
    }
    let cmd = {"type":"uiEle"};
    cmd.data = data;
    this.ws.send(JSON.stringify(cmd));
  }

}

class Map{
  eleId = 0;
  width=800;
  height=400;
  gridWidth = 10;
  assets;
  initAssets(){

  }
  
  addGrids(asstes){

  }

}

class Role{

  body;
  locX;
  locY;
  vx;
  vy;
  av;

  buttons=[1,2]
  skillA(){};
  skillB(){};
  skillC(){};
  skillD(){};
}

class Project{
  rooms=[];
  players={};
  commander;

  constructor(){
    this.commander = new Commander(this);
  }

  addPlayer(cname , ws){
    let player = new Player(cname , ws);
    this.players[cname]=player;
  }

  removePlayer(cname){
    delete this.players[cname];
  }

  getPlayer(pname){
    return this.players[pname];
  }

  rmsg(cname , msg){
    console.log("player "+ cname + " say: " + msg);
    let cmd;
    try{
      cmd = JSON.parse(msg);
    }catch(error){
      console.log(error.message);
    }

    if(!cmd){
      return;
    }
    if(!cmd.type){
      return;
    }
    if(!this.commander[cmd.type]){
      console.log("not a vaild cmd "+cmd.type);
      return;
    }
    this.commander[cmd.type](cname,cmd);

  }

  createRoom(nick,roomName){
    return("success");
  }

  getRooms(){
    return("success");
  }

  joinRoom(nick , roomName){
    return("success");
  }

  leaveRoom(nick , roomName){
    return("success");
  }



}

class Commander{

  project;

  constructor(project){
    this.project = project;
  }

  croom(pname,cmd){
    console.log(pname + " want create a room");
    let player = this.project.players[pname];
    if(this.project.rooms.length == 0){
      let room = new Room();
      room.admin = player;
      room.name = cmd.name ? cmd.name : pname+"'s root";
      room.players[pname] = player;
      player.room = room;
      this.project.rooms.push(room);
    }else if(player.inG){
      return;
    }else{
      let room = this.project.rooms[0];
      room.players[pname] = player;
      player.room = room;
    }

    let role = new Role();
    player.role = role;
  }

  joinRoom(pname , cmd ){
    console.log(pname + " join roome " + cmd.roomName);
  }

  leaveRoom(pname , cmd){
    console.log(pname + "leave the room");
  }

  startg(pname,cmd){
    console.log(pname + " start it");
    let player = this.project.getPlayer(pname);
    player.startg();
  }

  move(pname,cmd){
    let dv = this.getDir(cmd.dx,cmd.dy);
    let player = this.project.players[pname];
    player.move(dv[0],dv[1]);
  }

  stop(pname,cmd){
    let player = this.project.players[pname];
    player.move(0,0);
  }



  getDir(dx , dy){
    let hyp = Math.sqrt(dx*dx + dy*dy);
    // return [dx/hyp , dy / hyp];
    return [dx / 30, dy / 30];
  }


}

class Ele{
  shape = {
    type:"circle",
    r:50,
    color:"#07dff3ff",
    x : 400,
    y : 200
  }
  vx = 0;
  vy = 0;
  vrate = 10;
}





module.exports={
  Project
}
